package cn.ztydata.teachingsystem.heaven.web.controller;

import cn.ztydata.teachingsystem.common.Page;
import cn.ztydata.teachingsystem.exception.ServiceException;
import cn.ztydata.teachingsystem.exception.UploadException;
import cn.ztydata.teachingsystem.heaven.cons.FileNameCode;
import cn.ztydata.teachingsystem.heaven.cons.MsgTemplate;
import cn.ztydata.teachingsystem.heaven.cons.StudentAnswerStatus;
import cn.ztydata.teachingsystem.heaven.entity.Resource;
import cn.ztydata.teachingsystem.heaven.entity.Student;
import cn.ztydata.teachingsystem.heaven.entity.User;
import cn.ztydata.teachingsystem.heaven.entity.test.StudentAnswer;
import cn.ztydata.teachingsystem.heaven.entity.test.StudentTest;
import cn.ztydata.teachingsystem.heaven.entity.test.Test;
import cn.ztydata.teachingsystem.heaven.entity.test.TestExercise;
import cn.ztydata.teachingsystem.heaven.service.CourseGroupService;
import cn.ztydata.teachingsystem.heaven.service.StudentService;
import cn.ztydata.teachingsystem.heaven.service.TestService;
import cn.ztydata.teachingsystem.heaven.util.FileConverter;
import cn.ztydata.teachingsystem.heaven.util.UploadUtil;
import cn.ztydata.teachingsystem.heaven.web.dto.ResourceListDto;
import cn.ztydata.teachingsystem.heaven.web.dto.test.*;
import cn.ztydata.teachingsystem.heaven.web.wrapper.HttpSessionProxy;
import cn.ztydata.teachingsystem.util.StringCodeUtil;
import cn.ztydata.teachingsystem.webservice.result.json.JsonResult;
import cn.ztydata.teachingsystem.webservice.result.json.JsonResultData;
import cn.ztydata.teachingsystem.webservice.result.json.JsonResultList;
import cn.ztydata.teachingsystem.webservice.result.json.JsonResultPage;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.io.File;
import java.io.IOException;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 作业测试控制器类
 * Created by chenxin on 2015/3/18.
 */

@Controller
@RequestMapping("/test")
public class TestController extends BaseController {
    @Autowired
    private TestService testService;
    @Autowired
    private CourseGroupService groupService;
    @Autowired
    private StudentService studentService;
    @Autowired
    private FileConverter fileConverter;

    @Value("${file.dir}")
    private String uploadDir;

    @Value("${session.key}")
    private String sessionKey;

    /**
     * 学生作业测试列表
     *
     * @param type 作业类型
     * @param groupId 群组ID
     * @param method 作业方式
     * @param pageNum 当前页码
     * @param pageSize 每页条数
     * @param search 搜索关键字
     * @return json数据
     *
     * @author cx
     * @since 2015/03/19
     */
    @RequestMapping(value = "/studentList/{type}/{groupId}/{method}/{pageNum}/{pageSize}", method = RequestMethod.GET)
    @ResponseBody
    public JsonResult getStudentList(@PathVariable int type, @PathVariable long groupId, @PathVariable int method,
                                     @PathVariable int pageNum, @PathVariable int pageSize, @RequestParam String search) {
        //校验参数
        Assert.isTrue(type == 0 || type == 1, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "类型")); // 0：作业，1：测试
        Assert.isTrue(method >= 0 && method <= 2, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "方式")); // 0：线上，1：线下，2：全部
        Assert.isTrue(groupId > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "课程群组ID"));
        Assert.isTrue(pageNum > 0 && pageSize > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "分页参数"));

        //搜索关键字转码
        search = StringCodeUtil.urlParamTransCode(search, StringCodeUtil.UTF8);

        //获取列表
        Page<Test> pageTests = testService.getListForStudent(groupId, type, method, pageNum, pageSize, StringUtils.trim(search));

        //转为dto
        Page<TestListDto> result = new Page<>(pageTests.getTotal(), pageSize, pageNum, mapper.mapList(pageTests.getItems(), TestListDto.class));

        log.debug("return student test list");
        return new JsonResultPage<>(result);
    }

    /**
     * 学生作业统计图
     *
     * @param groupId 群组ID
     * @param type 作业类型
     * @param method 作业方式
     * @return json数据
     *
     * @author cx
     * @since 2015/03/20
     */
    @RequestMapping(value = "/statistic/{groupId}/{type}/{method}", method = RequestMethod.GET)
    @ResponseBody
    public JsonResult getStatisticForTest(@PathVariable long groupId, @PathVariable int type, @PathVariable int method, @RequestParam String keyword) {
        //校验参数
        Assert.isTrue(groupId > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "群组ID"));
        Assert.isTrue(type == 0 || type == 1, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "作业类型")); // 0：作业，1：测试
        Assert.isTrue(method >= 0 && method <= 2, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "作业方式")); // 0：线上，1：线下，2：全部

        //搜索关键字转换编码
        keyword = StringCodeUtil.urlParamTransCode(keyword, StringCodeUtil.UTF8);

        //获取作业统计信息
        List<Test> tests = testService.getStatisticList(groupId, type, method, StringUtils.trim(keyword));
        //转为dto
        List<TestListDto> result = mapper.mapList(tests, TestListDto.class);

        log.debug("学生作业统计图");
        return new JsonResultList<>(result);
    }

    /**
     * 学生最近作业、测试列表
     * 
     * @param type 作业类型
     * @param pageNum 当前页码
     * @param pageSize 每页条数
     * @return json数据
     * 
     * @author cx
     * @since 2015/3/20
     */
    @RequestMapping(value = "/studentCurrent/{type}/{pageNum}/{pageSize}", method = RequestMethod.GET)
    @ResponseBody
    public JsonResult getLastListForStudent(@PathVariable int type, @PathVariable int pageNum, @PathVariable int pageSize) {
        //校验参数
        Assert.isTrue(type == 0 || type == 1, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "类型"));
        Assert.isTrue(pageNum > 0 && pageSize > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "分页参数"));

        //获取作业列表
        Page<Test> pageTests = testService.getLastListForStudent(type, pageNum, pageSize);
        //转为dto
        Page<TestListDto> result = new Page<>(pageTests.getTotal(), pageSize, pageNum, mapper.mapList(pageTests.getItems(), TestListDto.class));

        log.debug("学生最近作业测试列表");
        return new JsonResultPage<>(result);
    }

    /**
     * 学生线下作业保存信息
     * 
     * @param testId 作业ID
     * @return json数据
     * 
     * @author cx
     * @since 2015/3/20
     */
    @RequestMapping(value = "/savedTestFile/{testId}", method = RequestMethod.GET)
    @ResponseBody
    public JsonResult getSavedTestFile(@PathVariable long testId) {
        //校验参数
        Assert.isTrue(testId > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "作业测试ID"));

        //获取保存的作业文件信息
        StudentTest studentTest = testService.getSavedTestFile(testId);

        log.debug("学生线下作业保存信息");
        //转为dto
        return new JsonResultData<>(mapper.map(studentTest, TestFileDto.class));
    }

    /**
     * 学生线下作业上传
     * 
     * @param testFile 作业文件
     * @param testId 作业ID
     * @return json数据
     * 
     * @author cx
     * @since 2015/3/20
     */
    @RequestMapping(value = "/saveTestFile", method = RequestMethod.POST)
    @ResponseBody
    public JsonResult saveTestFile(@RequestParam MultipartFile testFile, @RequestParam long testId) {
        //校验参数
        Assert.isTrue(testId > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "作业测试ID"));

        //定义文件上传类型白名单
        List<String> fileTypes = Lists.newArrayList("doc", "docx");

        //校验上传的文件
        UploadUtil.validateFile(testFile, fileTypes);

        //获取上传文件的原始名称
        String originalFileName = testFile.getOriginalFilename();
        //获取上传文件的扩展名
        String fileExt = UploadUtil.getFileExt(originalFileName);
        //定义文件的存储路径
        String saveDir = UploadUtil.generateFolderByDate() + "/" + UploadUtil.generateFileName(fileExt);

        //写入文件
        File file = new File(uploadDir, saveDir);
        try {
            FileUtils.writeByteArrayToFile(file, testFile.getBytes());
        } catch (IOException e) {
            log.debug("上传文件发生IO异常");
            log.warn("上传文件发生IO异常",e);

            return new JsonResult(false, "上传作业失败");
        }

        //保存上传作业文件的相对路径
        StudentTest studentTest = new StudentTest();

        studentTest.setTestId(testId);
        studentTest.setSubmittedFileName(originalFileName);
        studentTest.setSubmittedDownPath("/" + saveDir);

        testService.saveOfflineTest(studentTest);

        Map<String, String> result = Maps.newHashMap();
        result.put("downloadUrl", saveDir);

        log.debug("学生上传作业成功");
        return new JsonResultData<>(result, "上传成功");
    }

    /**
     * 学生线下作业删除（未提交）
     * @param testId 作业ID
     * @return json
     * 
     * @author cx
     * @since 2015/3/21
     */
    @RequestMapping(value = "/deleteTestFile/{testId}", method = RequestMethod.DELETE)
    @ResponseBody
    public JsonResult deleteTestFile(@PathVariable long testId) {
        //校验参数
        Assert.isTrue(testId > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "作业测试ID"));

        //删除学生未提交的线下作业
        testService.deleteTestFile(testId);

        log.debug("删除学生线下作业");
        return new JsonResult(true, "删除成功");
    }

    /**
     * 学生线下作业提交
     * @param studentTestDto 学生作业dto
     * @return json
     * 
     * @author cx
     * @since 2015/3/21
     */
    @RequestMapping(value = "/submitOfflineTest", method = RequestMethod.PUT)
    @ResponseBody
    public JsonResult submitOfflineTest(@Valid @RequestBody StudentTestDto studentTestDto) {
        //更新学生线下作业状态
        testService.submitOfflineTest(studentTestDto.getTestId());

        log.debug("学生线下作业提交");
        return new JsonResult(true, "提交成功");
    }

    /**
     * 线上作业答题-习题列表
     * 
     * @param testId 作业测试ID
     * @return json
     * 
     * @author cx
     * @since 2015/3/23
     */
    @RequestMapping(value = "/onlinePraxisList/{testId}", method = RequestMethod.GET)
    @ResponseBody
    public JsonResult getExercisesForTest(@PathVariable long testId) {
        //校验参数
        Assert.isTrue(testId > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "作业测试ID"));

        //获取登录学生作答自己作业时停留在的习题ID
        long positionId = testService.getLastExercisePosition(testId);

        //获取作业的习题列表信息
        List<TestExercise> testExercises = testService.getTestExercises(testId);
        //转为dto
        List<TestExerciseDto> testExercisesDto = mapper.mapList(testExercises, TestExerciseDto.class);

        Map<String, Object> result = Maps.newHashMap();

        result.put("positionId", positionId);
        result.put("praxisList", testExercisesDto);

        log.debug("线上作业答题-习题列表");
        return new JsonResultData<>(result);
    }

   /**
     * 教师作业/测试列表
     * @param type 类型（0：作业，1：测试）
     * @param groupId 课程群组编号（0：全部）
     * @param method 方式（0：线上，1：线下，2：全部）
     * @param currentPage 页码
     * @param pageSize 每页显示条数
     * @return JsonResult
     *
     * @author fanruiping
     * @since 2015-03-20
     */
    @ResponseBody
    @RequestMapping(value = "/teacherList/{type}/{groupId}/{method}/{currentPage}/{pageSize}",method = RequestMethod.GET)
    public JsonResult getTeacherTestList(@PathVariable int type,@PathVariable Long groupId,@PathVariable int method,
                                         @PathVariable int currentPage,@PathVariable int pageSize,@RequestParam("search") String keyword,
                                         HttpServletRequest request){
        //校验参数
        Assert.isTrue(groupId >= 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "群组ID"));
        Assert.isTrue(type == 0 || type == 1, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "作业类型"));
        Assert.isTrue(method >= 0 && method <= 2, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "作业方式"));
        Assert.isTrue(currentPage > 0 && pageSize > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "分页参数"));

        //搜索关键字转码
        keyword = StringCodeUtil.urlParamTransCode(keyword, StringCodeUtil.UTF8);

        //获取session
        HttpSessionProxy httpSessionProxy = (HttpSessionProxy)request.getSession();

        //获取当前用户信息
        User entity = (User)httpSessionProxy.getAttribute(sessionKey);

        //教师作业/测试列表
        Page<Test> testPage = testService.getListForTeacher(Long.valueOf(0),Long.valueOf(0),entity.getUserId(),keyword,groupId,type,method,currentPage,pageSize);

        //Entity转Dto
        Page<TestListDto> listDtoPage = new Page<>(testPage.getTotal(),testPage.getSize(),testPage.getNum(),mapper.mapList(testPage.getItems(),TestListDto.class));

        return new JsonResultPage<>(listDtoPage);
    }

    /**
     * 新增作业/测试
     * @param testInfoDto
     * @return JsonResult
     *
     * @author fanruiping
     * @since 2015-03-21
     */
    @ResponseBody
    @RequestMapping(value = "/add", method = RequestMethod.POST)
    public JsonResult add(@RequestBody TestInfoDto testInfoDto,HttpServletRequest request){
        //获取session
        HttpSessionProxy httpSessionProxy = (HttpSessionProxy)request.getSession();

        //获取当前用户信息
        User entity = (User)httpSessionProxy.getAttribute(sessionKey);

        //Dto转Entity
        Test test = mapper.map(testInfoDto,Test.class);

        //设定创建人为当前用户编号
        test.setCreatorId(entity.getUserId());

        try{
            //判断方式是否是线上
            if(0 == test.getMethod()){
                log.debug("作业答题方式为线上:0 == test.getMethod()");

                testService.addOnline(test);
            }else{
                log.debug("作业答题方式为线下");

                testService.addOffline(test);

                //判断是否上传了作业或测试word
                if((test.getResourceId() == null || test.getResourceId() == 0) && !test.getTestDownloadPath().isEmpty()){
                    log.debug("线下作业包含附件:!test.getTestDownloadPath().isEmpty()");

                    fileConverter.newTask("test:"+ FileNameCode.testMap.get(1)+":"+test.getId());
                }

                //判断是否上传了作业或测试答案word
                if(!test.getAnswerDownloadPath().isEmpty()){
                    log.debug("线下作业包含答案附件:!test.getTestDownloadPath().isEmpty()");

                    fileConverter.newTask("test:"+ FileNameCode.testMap.get(2)+":"+test.getId());
                }
            }

            return new JsonResult(true, "作业或测试数据添加成功");
        }catch (IOException ex){
            log.debug("作业附件转换异常:IOException ex");

            log.warn("作业或测试附件转换io异常:"+ex.getMessage());

            return new JsonResult(true, "作业或测试数据添加成功");
        }catch (ServiceException ex){
            log.debug("作业或测试数据添加失败:ServiceException ex");

            return new JsonResult(false, ex.getMessage());
        }
    }

    /**
     * 引用已有作业新增
     * @param testId 被引用作业编号
     * @param testInfoDto 引用新增作业信息
     * @return JsonResult
     *
     * @author fanruiping
     * @since 2015-03-21
     */
    @ResponseBody
    @RequestMapping(value = "/addRepeat/{testId}", method = RequestMethod.POST)
    public JsonResult addRepeat(@PathVariable Long testId,@RequestBody TestInfoDto testInfoDto,HttpServletRequest request){
        //获取session
        HttpSessionProxy httpSessionProxy = (HttpSessionProxy)request.getSession();

        //获取当前用户信息
        User entity = (User)httpSessionProxy.getAttribute(sessionKey);

        //校验参数
        Assert.isTrue(testId > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "被引用作业或测试编号"));

        try{
            //Dto转Entity
            Test test = mapper.map(testInfoDto,Test.class);

            //设定创建人为当前用户编号
            test.setCreatorId(entity.getUserId());
            //引用新增
            testService.repeatAdd(test, testId);

            return new JsonResult(true,"引用作业或测试成功");
        }catch(ServiceException ex){
            log.debug("引用作业或测试数据失败:ServiceException ex");

            return new JsonResult(false,ex.getMessage());
        }
    }

    /**
     * 编辑作业明细
     * @param testId 作业编号
     * @return JsonResult
     *
     * @author fanruiping
     * @since 2015-03-27
     */
    @ResponseBody
    @RequestMapping(value = "/editDetail/{testId}", method = RequestMethod.GET)
    public JsonResult editDetail(@PathVariable Long testId){
        return new JsonResultData<>(mapper.map(testService.detailForEdit(testId),TestInfoDto.class));
    }

    /**
     * 更新作业数据
     * @param test 作业实体
     * @return JsonResult
     *
     * @author fanruiping
     * @since 2015-03-27
     */
    @ResponseBody
    @RequestMapping(value = "/editSave", method = RequestMethod.PUT)
    public JsonResult editSave(@RequestBody TestInfoDto test){
        Test testDetail = mapper.map(test, Test.class);
        try {
            testService.update(testDetail);

            //判断是否上传了作业或测试word
            if ((test.getResourceId() == null || test.getResourceId() == 0) && !testDetail.getTestDownloadPath().isEmpty()) {
                log.debug("线下作业包含附件:!test.getTestDownloadPath().isEmpty()");

                fileConverter.newTask("test:" + FileNameCode.testMap.get(1) + ":" + testDetail.getId());
            }

            //判断是否上传了作业或测试答案word
            if (!testDetail.getAnswerDownloadPath().isEmpty()) {
                log.debug("线下作业包含答案附件:!test.getTestDownloadPath().isEmpty()");

                fileConverter.newTask("test:" + FileNameCode.testMap.get(2) + ":" + testDetail.getId());
            }
        }catch (IOException ex){
            log.debug("作业附件转换异常:IOException ex");

            log.warn("作业或测试附件转换io异常:"+ex.getMessage());
        }

        return new JsonResult(true,"作业或测试数据更新成功");
    }

    /**
     * 作业/测试明细（线上）
     * @param testId 作业比那好
     * @return JsonResult
     *
     * @author fanruiping
     * @since 2015-03-27
     */
    @ResponseBody
    @RequestMapping(value = "/detailOnline/{testId}", method = RequestMethod.GET)
    public JsonResult detailOnline(@PathVariable Long testId){
        return new JsonResultData<>(mapper.map(testService.onlineDetail(testId),TestInfoDto.class));
    }

    /**
     * 作业/测试明细（线下）
     * @param testId 作业编号
     * @return JsonResult
     *
     * @author fanruiping
     * @since 2015-03-27
     */
    @ResponseBody
    @RequestMapping(value = "/detailOffline/{testId}", method = RequestMethod.GET)
    public JsonResult detailOffline(@PathVariable Long testId,HttpServletRequest request){
        //获取session
        HttpSessionProxy httpSessionProxy = (HttpSessionProxy)request.getSession();

        //获取当前用户信息
        User entity = (User)httpSessionProxy.getAttribute(sessionKey);

        return new JsonResultData<>(mapper.map(testService.offlineDetail(testId,entity),TestInfoDto.class));
    }

    /**
     * 作业明细（批阅）
     * @param testId
     * @return JsonResult
     *
     * @author fanruiping
     * @since 2015-04-02
     */
    @ResponseBody
    @RequestMapping(value = "/correctInfo/{testId}", method = RequestMethod.GET)
    public JsonResult correctInfo(@PathVariable Long testId,HttpServletRequest request){
        //获取session
        HttpSessionProxy httpSessionProxy = (HttpSessionProxy)request.getSession();

        //获取当前用户信息
        User entity = (User)httpSessionProxy.getAttribute(sessionKey);

        TestInfoDto testInfoDto = mapper.map(testService.offlineDetail(testId,entity), TestInfoDto.class);

        testInfoDto.setTeacher(groupService.getTeacherNameById(testInfoDto.getGroupId()));

        return new JsonResultData<>(testInfoDto);
    }

    /**
     * 删除作业或测试数据
     * @param id 作业或测试编号
     * @return JsonResult
     *
     * @author fanruiping
     * @since 2015-03-27
     */
    @ResponseBody
    @RequestMapping(value = "/delete/{id}", method = RequestMethod.DELETE)
    public JsonResult delete(@PathVariable Long id){
        testService.delete(id);

        return new JsonResult(true,"作业或测试数据删除成功");
    }

    /**
     * 作业明细（统计）
     * @param testId 习题编号
     * @return JsonResult
     *
     * @author fanruiping
     * @since 2015-04-01
     */
    @ResponseBody
    @RequestMapping(value = "/statisticsDetail/{testId}")
    public JsonResult statisticsDetail(@PathVariable Long testId){
        return new JsonResultData<>(mapper.map(testService.statisticsDetail(testId),TestInfoDto.class));
    }

    /**
     * 获取指定作业下的学生及批阅状态(统计页面)
     * @param testId 作业编号
     * @return JsonResult
     *
     * @author fanruiping
     * @since 2015-03-31
     */
    @ResponseBody
    @RequestMapping(value = "/correctStudentList/{groupId}/{testId}", method = RequestMethod.GET)
    public JsonResult correctStudentList(@PathVariable Long groupId,@PathVariable Long testId){
        return new JsonResultList<>(mapper.mapList(testService.getStudentsByTestId(testId), StudentTestDto.class));
    }

    /**
     * 指定习题的学生答题情况
     * @param testId
     * @param exerciseId
     * @return JsonResult
     *
     * @author fanruiping
     * @since 2015-04-02
     */
    @ResponseBody
    @RequestMapping(value = "/correctStudent/{testId}/{exerciseId}")
    public JsonResult correctStudent(@PathVariable Long testId,@PathVariable Long exerciseId){
        return new JsonResultList<>(mapper.mapList(testService.getTestExerciseStatistics(testId,exerciseId), StudentAnswerDto.class));
    }

    /**
     * 学生习题列表（批阅页面）
     * @param studentId 学生编号
     * @param testId 作业编号
     * @return JsonResult
     *
     * @author fanruiping
     * @since 2015-04-02
     */
    @ResponseBody
    @RequestMapping(value = "/studentPraxisList/{studentId}/{testId}", method = RequestMethod.GET)
    public JsonResult studentPraxisList(@PathVariable Long studentId, @PathVariable Long testId){
        return new JsonResultList<>(mapper.mapList(testService.getExerciseScoreByStudentId(testId,studentId),StudentAnswerDto.class));
    }

    /**
     * 学生作业明细
     * @param testId 作业编号
     * @param studentId 学生编号
     * @return JsonResult
     *
     * @author fanruiping
     * @since 2015-04-02
     */
    @ResponseBody
    @RequestMapping(value = "/studentScore/{testId}/{studentId}/{line}", method = RequestMethod.GET)
    public JsonResult studentScore(@PathVariable Long testId, @PathVariable Long studentId, @PathVariable int line,HttpServletRequest request){
        //获取session
        HttpSessionProxy httpSessionProxy = (HttpSessionProxy)request.getSession();

        //获取当前用户信息
        User entity = (User)httpSessionProxy.getAttribute(sessionKey);

        //获取指定学生作业信息
        StudentTestDto studentTest = mapper.map(testService.getStudentTestDetail(testId,studentId,entity),StudentTestDto.class);

        //获取学生信息
        Student student = studentService.getDetail(studentId);

        //插入学生头像
        if(student != null){
            log.debug("未获取到指定学生的详细信息:student != null");

            studentTest.setPhoto(student.getAvatar());
        }

        return new JsonResultData<>(studentTest);
    }

    /**
     * 批阅线下作业测试
     * @param studentTestDto 学生作业
     * @return JsonResult
     *
     * @author fanruiping
     * @since 2015-04-02
     */
    @ResponseBody
    @RequestMapping(value = "/offlineScoreSave",method = RequestMethod.PUT)
    public JsonResult offlineScoreSave(@RequestBody StudentTestDto studentTestDto){
        testService.readOverOfflineTest(mapper.map(studentTestDto,StudentTest.class));

        return new JsonResult(true,"批阅线下作业或测试成功");
    }

   /**
     * 保存学生线上答题
     *
     * @param studentAnswerDto 学生答题dto
     * @return json
     *
     * @author cx
     * @since 2015/3/31
     */
    @RequestMapping(value = "/studentAnswerPraxis", method = RequestMethod.PUT)
    @ResponseBody
    public JsonResult saveAnswer(@Valid @RequestBody StudentAnswerDto studentAnswerDto) {
        //转为实体类
        StudentAnswer studentAnswer = mapper.map(studentAnswerDto, StudentAnswer.class);

        //保存学生的答题
        testService.saveStudentAnswer(studentAnswer);

        Map<String, Object> result = Maps.newHashMap();
        if (studentAnswer.getStatus() == StudentAnswerStatus.NOT_ANSWER) {
            log.debug("学生答题状态为未答:studentAnswer.getStatus() == StudentAnswerStatus.NOT_ANSWER");
            result.put("answerStatus", StudentAnswerStatus.NO_ANSWER);
        }
        else {
            log.debug("学生答题状态为已答");
            result.put("answerStatus", StudentAnswerStatus.HAS_ANSWER);
        }

        log.debug("保存成功");
        return new JsonResultData<>(true, "保存成功", result);
    }

    /**
     * 线上作业提交
     * 
     * @param studentTestDto 学生作业dto
     * @return json
     * 
     * @author cx
     * @since 2015/3/31
     */
    @RequestMapping(value = "/submitOnlineTest", method = RequestMethod.PUT)
    @ResponseBody
    public JsonResult submitOnlineTest(@Valid @RequestBody StudentTestDto studentTestDto) {
        testService.submitOnlineTest(studentTestDto.getTestId());

        log.debug("线上作业提交");
        return new JsonResult(true, "提交成功");
    }

    /**
     * 批阅主观题
     * @param studentAnswerDto 学生答题
     * @return JsonResult
     *
     * @author fanruiping
     * @since 2015-04-02
     */
    @ResponseBody
    @RequestMapping(value = "/subjectiveSave", method = RequestMethod.PUT)
    public JsonResult subjectiveSave(@RequestBody StudentAnswerDto studentAnswerDto){
        int hasReadOver = testService.readOverSubjective(mapper.map(studentAnswerDto, StudentAnswer.class));

        Map<String, String> result = Maps.newHashMap();
        result.put("correct", String.valueOf(hasReadOver));

        return new JsonResultData<>(true, "批阅主观题成功", result);
    }


    /**
     * 已有作业/测试列表
     * @param page 页码
     * @param pageSize 每页显示条数
     * @param courseId 课程编号
     * @param chapterId 章节编号
     * @param method 方式（0:线上，1：线下）
     * @param type 类型（0：作业，1：测试）
     * @param request 请求
     * @return JsonResult
     *
     * @author fanruiping
     * @since 2015-04-06
     */
    @ResponseBody
    @RequestMapping(value = "/historyList/{page}/{pageSize}/{courseId}/{chapterId}/{method}/{type}",method = RequestMethod.GET)
    public JsonResult getTeacherTestList(@PathVariable int page,@PathVariable int pageSize,@PathVariable Long courseId,
            @PathVariable Long chapterId,@PathVariable int method,@PathVariable int type,HttpServletRequest request){
        //校验参数
        Assert.isTrue(courseId >= 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "课程编号"));
        Assert.isTrue(chapterId >= 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "章节编号"));
        Assert.isTrue(type == 0 || type == 1, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "类型"));
        Assert.isTrue(method == 0 || method == 1, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "方式"));
        Assert.isTrue(page > 0 && pageSize > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, "分页参数"));

        //获取session
        HttpSessionProxy httpSessionProxy = (HttpSessionProxy)request.getSession();

        //获取当前用户信息
        User entity = (User)httpSessionProxy.getAttribute(sessionKey);

        //教师作业/测试列表
        Page<Test> testPage = testService.getListForTeacher(courseId,chapterId,entity.getUserId(),"",Long.valueOf(0),type,method,page,pageSize);

        //Entity转Dto
        Page<TestListDto> listDtoPage = new Page<>(testPage.getTotal(),testPage.getSize(),testPage.getNum(),mapper.mapList(testPage.getItems(),TestListDto.class));

        return new JsonResultPage<>(listDtoPage);
    }

    /**
     * 上传文件
     * @param type 类型（0：作业问题附件、1：作业答案附件）
     * @return JsonResult
     *
     * @author fanruiping
     * @since 2015-04-07
     */
    @ResponseBody
    @RequestMapping(value = "/upload/{type}", method = RequestMethod.POST)
    public JsonResult upload(@PathVariable int type,@RequestParam("data") MultipartFile coverFile){
        //定义允许上传的图片类型
        List fileTypes = Lists.newArrayList("doc","docx");
        String url = null;

        try {
            //校验上传的文件
            UploadUtil.validateFile(coverFile, fileTypes);

            //保存上传的图片
            String fileExt = UploadUtil.getFileExt(coverFile.getOriginalFilename());

            //生成文件上传地址
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            url = "/"+sdf.format(new Date())+"/"+ UploadUtil.generateFileName(fileExt);

            File file = new File(uploadDir, url);
            FileUtils.writeByteArrayToFile(file, coverFile.getBytes());

            log.debug("word文件上传成功");

            return new JsonResultData<>(url,"word文件上传成功");
        } catch (IOException | UploadException | ServiceException ex) {
            log.debug("作业附件上传失败:IOException | UploadException | ServiceException ex");

            return new JsonResult(false, ex.getMessage().isEmpty() ? "上传失败" : ex.getMessage());
        }
    }

    /**
     * 作业附件转换
     * @param testId 作业编号
     * @param type 附件类型(0:问题,1:答案,2:批阅文件,3:学生作业)
     * @param studentId 学生编号
     * @return JsonResult
     *
     * @author fanruiping
     * @since 2015-04-06
     */
    @ResponseBody
    @RequestMapping(value = "/convertOffLine/{testId}/{type}/{studentId}", method = RequestMethod.PUT)
    public JsonResult convertOffLine(@PathVariable Long testId, @PathVariable int type,@PathVariable Long studentId){
        StudentTest stFileInfo = null;

        if (type == 2 || type == 3){
            //获取学生作业的文件信息
            stFileInfo = testService.getSTFileInfo(studentId,testId);
        }

        try {
            if(0 == type){
                log.debug("待转换文件类型:作业问题附件:0 == type");

                fileConverter.newTask("test:"+ FileNameCode.testMap.get(1) +":"+ testId);
            }else if(1 == type){
                log.debug("待转换文件类型:作业答案附件:1 == type");

                fileConverter.newTask("test:"+ FileNameCode.testMap.get(2) +":"+ testId);
            }else if(2 == type && null != stFileInfo){
                log.debug("待转换文件类型:学生作业批阅附件:2 == type");

                fileConverter.newTask("studentTest:"+ FileNameCode.studentTestMap.get(2) +":"+ stFileInfo.getId());
            }else if(3 == type && null != stFileInfo){
                log.debug("待转换文件类型:学生作业附件:3 == type");

                fileConverter.newTask("studentTest:"+ FileNameCode.studentTestMap.get(1) +":"+ stFileInfo.getId());
            }
        }catch (IOException ex){
            log.debug("文件转换异常:IOException ex");

            log.error("文件转换IO异常");
        }

        return new JsonResult(true,"文件正在转换，请刷新查看");
    }

    /**
     * 作业批阅文件上传
     * @param coverFile 文件
     * @return JsonResult
     *
     * @author fanruiping
     * @since 2015-04-07
     */
    @ResponseBody
    @RequestMapping(value = "/attachmentUpload", method = RequestMethod.POST)
    public JsonResult uploadReadOverFile(@RequestParam Long testId,@RequestParam Long studentId,@RequestParam String correctFileName,
                                         @RequestParam("data") MultipartFile coverFile){

        //定义允许上传的图片类型
        List fileTypes = Lists.newArrayList("doc","docx");
        String url = null;

        try {
            //校验上传的文件
            UploadUtil.validateFile(coverFile, fileTypes);

            //保存上传的图片
            String fileExt = UploadUtil.getFileExt(coverFile.getOriginalFilename());

            //生成文件上传地址
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            url = "/"+sdf.format(new Date())+"/"+ UploadUtil.generateFileName(fileExt);

            File file = new File(uploadDir, url);
            FileUtils.writeByteArrayToFile(file, coverFile.getBytes());

            //获取学生作业明细
            StudentTest detail = testService.getStudentTestSimpleDetail(testId,studentId);
            //判断未获取到作业明细
            if(null == detail){
                log.debug("未获取到指定学生作业详细:null == detail");

                return new JsonResult(false, "学生作业不存在");
            }

            //更新批阅文件地址
            testService.updateReadOverFile(testId,studentId, correctFileName, url);

            //转换文件
            fileConverter.newTask("studentTest:"+ FileNameCode.studentTestMap.get(2) +":"+ detail.getId());

            Map<String, String> result = Maps.newHashMap();
            result.put("downloadUrl", url);

            return new JsonResultData<>(true,"word文件上传成功", result);
        } catch (IOException ex) {
            log.debug("学生作业批阅文件转换失败:IOException ex");

            log.warn("word文件转换失败:url->" + url, ex);

            return new JsonResult(false, "文件转换失败");
        } catch (UploadException | ServiceException ex) {
            log.debug("学生作业批阅文件信息更新失败:UploadException | ServiceException ex");

            return new JsonResult(false, ex.getMessage().isEmpty() ? "上传失败" : ex.getMessage());
        }
    }

    /**
     * 删除批阅文件
     * @param testId 作业编号
     * @param studentId 学生编号
     * @return JsonResult
     *
     * @author fanruiping
     * @since 2015-04-06
     */
    @ResponseBody
    @RequestMapping(value = "/deleteCorrectFile/{testId}/{studentId}", method = RequestMethod.DELETE)
    public JsonResult deleteCorrectFile(@PathVariable Long testId,@PathVariable Long studentId){
       testService.deleteReadOverFile(testId,studentId);

        return new JsonResult(true,"删除批阅文件成功");
    }

    /**
     * 教师查看成绩页面
     * @param testId 作业编号
     * @return JsonResult
     *
     * @author fanruiping
     * @since 2015-04-07
     */
    @ResponseBody
    @RequestMapping(value = "/score/{testId}", method = RequestMethod.GET)
    public JsonResult score(@PathVariable Long testId){
        return new JsonResultData<>(mapper.map(testService.getAllStudentScore(testId),TestInfoDto.class));
    }

    /**
     * 作业习题资源解析
     * @param testId 作业ID
     * @param exerciseId 习题ID
     * @return json
     * 
     * @author cx
     * @since 2015/4/23
     */
    @RequestMapping(value = "/praxisResources/{testId}/{exerciseId}", method = RequestMethod.GET)
    @ResponseBody
    public JsonResult getPraxisResources(@PathVariable long testId, @PathVariable long exerciseId) {
        //校验参数
        Assert.isTrue(testId > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, testId));
        Assert.isTrue(exerciseId > 0, MessageFormat.format(MsgTemplate.ARG_VALIDATION_ERR, exerciseId));

        //获取作业习题的资源解析
        List<Resource> resources = testService.getResourcesOfTE(testId, exerciseId);
        
        log.debug("作业习题资源解析");
        return new JsonResultList<>(mapper.mapList(resources, ResourceListDto.class));
    }
}
